var fs = ( function() {

	var stores = {
		initLocal : function() {
		    var result = $.Deferred();
			try {
				var localStore = new Local();
				localStore.init();
				stores.local = localStore;
			} catch (e) {
				console.log("Unable to intilise Web Local Store due to: '"+e+"'");
			} finally {
				delete stores["initLocal"];
			}
			return result.promise();
		},
		initDropbox : function(key) {
		    var result = $.Deferred();
			try {
				var dropboxStore = new DropboxFS(key);
				dropboxStore.init()
				.then(function(user) {
					stores.remote = dropboxStore;
					delete stores["initDropbox"];
					result.resolve(user);
				})
				.fail(function(e) {
					console.log("Unable to intilise DropboxFS Store due to: '"+e+"'");
					result.resolve();
				});
			} catch (e) {
				console.log("Unable to intilise DropboxFS due to: '"+e+"'");
				result.resolve();
			}
			return result.promise();
		},
		initGlobal : function(rootUrl) {
			stores.global = new Global(rootUrl);
			delete stores["initGlobal"];
			return stores.global;
		}
	}

	var DropboxFS = ( function() {

	    function DropboxFS(key) {
	    	this.mDropboxClient = new Dropbox.Client({ key: key });
			this.mDropboxClient.authDriver(new Dropbox.AuthDriver.Redirect({
				rememberUser: true
			}));
	    }

	    DropboxFS.prototype.init = function() {
	    	var result = $.Deferred();
	    	var self = this;
			this.mDropboxClient.authenticate(function(error, data) {
				if (error)
				{
					result.reject(error);
				}
				self.mDropboxClient.getUserInfo(function(error, userInfo) {
					if (error) {
						result.reject(error);
					}
					result.resolve(userInfo.name);
					this.mUserInfo = userInfo;
				});
			});
			return result.promise();
	    }

	    DropboxFS.prototype.name = function() {
	    	 return "remote::dropbox("+this.mUserInfo.name+")";
	    }

	    DropboxFS.prototype.readFolder = function(path) {
	    	var result = $.Deferred();
	    	var self = this;
			this.mDropboxClient.readdir(path, function(error, entries, dir_stat, entry_stats)
			{
				if (error)
				{
					result.reject(error);
					return;
				}

				var contents = {
					folders : [],
					files   : []
				}
				for (i = 0 ; i < entry_stats.length; i++)
				{
					if (entry_stats[i].isFolder) {
						folders.push(entry_stats[i]);
					} else {
						file.push(entry_stats[i]);
					}
				}
				result.resolve(contents);
			});
			return result.promise();
	    }

	    DropboxFS.prototype.exists = function(path) {
	    	var result = $.Deferred();
	    	this.mDropboxClient.stat(path, function(error, stat) {
	    		if (error) {
	    			if (error.status == 404 ) {
	    				result.resolve(false);
	    				return;
	    			}
	    			result.reject(error);
	    		} else {
	    			result.resolve(true);
	    		}
	    	});
	    	return result.promise();
	    }

	    DropboxFS.prototype.read = function(path) {
	    	var result = $.Deferred();
	    	var self = this;
			this.mDropboxClient.readFile(path, function(error, data, stat) {
				if (error)
				{
					if (error.status != 404) {
						error.notFound = true;
					}
					result.reject(error);
					return;
				}
				result.resolve(data);
			});
			return result.promise();
	    }

	    DropboxFS.prototype.mkdir = function(path) {
	    	var result = $.Deferred();
	    	var self = this;
			this.mDropboxClient.mkdir(path, function(error, stat) {
				if (error)
				{
					result.reject(error);
					return;
				}
				result.resolve();
			});
			return result.promise();
	    }


	    DropboxFS.prototype.delete = function(path) {
	    	var result = $.Deferred();
	    	var self = this;
	    	if (path == "/") {
	    		this.readFolder(path).pipe(function(pathContents) {
	    			var tasks = [];
	    			function addDeletTask(elemPath) {
	    				tasks.push( function() {
	    					self.delete(elemPath)
	    				});
	    			}
	    			for (var i = 0; i < pathContents.files.length; i++) {
	    				addDeletTask(pathContents.files[i].name);
	    			}
	    			for (var i = 0; i < pathContents.folders.length; i++) {
	    				addDeletTask(pathContents.files[i].name);
	    			}
	    			return pipeline(tasks);
	    		});
	    	} else {
				this.mDropboxClient.remove(path, function(error, stat) {
					if (error && error.status != 404)
					{
						result.reject(error);
						return;
					}
					result.resolve();
				});
	    	}
			return result.promise();
	    }


	    DropboxFS.prototype.write = function(path, data) {
	    	var result = $.Deferred();
	    	var self = this;
			this.mDropboxClient.writeFile(path, function(error, stat) {
				if (error) {
					result.reject(error);
					return;
				}
				result.resolve();
			});
			return result.promise();
	    }

	    return DropboxFS;
	})();





	var Local = ( function() {

	    function Local() {
	    }

	    Local.prototype.name = function() {
	    	 return "local";
	    }

	    Local.prototype.init = function() {
	    	if (!('localStorage' in window && window['localStorage'] !== null)) {
				throw new Error("No local storage here.");
	    	}
	    	return $.Deferred().resolve().promise();
	    }

	    Local.prototype.exists = function(path) {
	    	if (!path) {
	    		return false;
	    	}
	    	for ( var storageEntryKey in window.localStorage ) {
	    		var i = 0;
	    		for (; i < path.length; i++) {
	    			if (path[i] != storageEntryKey[i]) {
	    				break;
	    			}
	    		}
	    		if (i == path.length) {
	    			return true;
	    		}
			}
			return false;
	    }

	    Local.prototype.read = function(path) {
	    	if (this.exists(path)) {
	    		return window.localStorage[path];
	    	}
	    	var error = new Error("Path "+path+" not found in Local storage");
	    	error.notFound = true;
	    	throw error;
	    }

	    Local.prototype.write = function(path, data) {
	    	window.localStorage[path] = data;
	    }

	    Local.prototype.delete = function(path) {
	    	for (var storageEntryKey in window.localStorage) {
	    		var matches = true;
	    		for (var i = 0; i < path.length; i++) {
	    			if (path[i] != storageEntryKey[i]) {
	    				matches = false;
	    			}
	    		}
	    		if (matches) {
	    			window.localStorage.removeItem(storageEntryKey);
	    		}
	    	}
	    }

	    return Local;
	})();




	var Global = ( function() {

	    function Global(rootUrl) {
	    	this.mRootUrl = rootUrl;
	    }

	    Global.prototype.read = function(path) {
            var result = $.Deferred();
            jQuery.get(this.mRootUrl+"/"+path, function(data) {
                result.resolve(data);
            })
            .fail(function(e) {
            	if (e && e.status == 404) {
            		e.notFound = true;
            	}
                result.reject(e);
            });

            return result.promise();
	    }

	    Global.prototype.name = function() {
	    	 return "global ("+this.mRootUrl+")";
	    }

	    return Global;
	})();


	return stores;
})();
